﻿using AdminSystem.Application.Addresss;
using AdminSystem.Application.Admins;
using AdminSystem.Domain;
using AdminSystem.EntityFrameworkCore;
using AdminSystem.Repositories;
using AdminSystem.WebApi;
using AdminSystem.WebApi.Models;
using Lazy.Captcha.Core.Generator;
using Lazy.Captcha.Core;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Filters;
using Swashbuckle.AspNetCore.SwaggerUI;
using System.Reflection;
using System.Text;
using Microsoft.Extensions.Hosting.WindowsServices;
using AdminSystem.Application;
using Quartz.Impl;
using Quartz.Spi;
using Quartz;

var options = new WebApplicationOptions
{
    Args = args,
    ContentRootPath = WindowsServiceHelpers.IsWindowsService() ? AppContext.BaseDirectory : default
};

var builder = WebApplication.CreateBuilder(options);



// Add services to the container.
// 添加服务到容器-----给容器添加服务---注册

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();

// 配置Quartz
builder.Services.AddQuartz(q =>
{
    q.SchedulerId = "Scheduler-Core";
    q.SchedulerName = "Quartz ASP.NET Core Sample Scheduler";
    q.UseSimpleTypeLoader();
    q.UseInMemoryStore();
    q.UseDefaultThreadPool(tp =>
    {
        tp.MaxConcurrency = 10;
    });

    q.AddJob<MyJob>(j => j
        .StoreDurably()
        .WithIdentity("job1")
        .WithDescription("A job to say hello world.")
    );

    q.AddTrigger(t => t
        .ForJob("job1")
        .WithIdentity("trigger1")
        .WithCronSchedule("0 0 0 * * ?")
        .WithDescription("Every 5 seconds")
    );
});

builder.Services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);


//db上下文
builder.Services.AddDbContext<AdminSystemDbContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("SqlServer")).AddInterceptors(new SoftDeleteInterceptor());
});


//IoC -- 控制反转  DI -- 依赖注入--向ioc容器注册
builder.Services.AddScoped<IAdminService, AdminService>();
builder.Services.AddScoped<IAddressService, AddressService>();
builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
builder.Services.AddScoped<IAdminRepository, AdminRepository>();

// 注册 Quartz 服务
/*builder.Services.AddScoped<IQuartzDemoService, QuartzDemoService>();
builder.Services.AddSingleton<IJob, MyJob>();
builder.Services.AddSingleton<IJobFactory, DefaultScheduleServiceFactory>();*/

//AutoMapper
builder.Services.AddAutoMapper(Assembly.Load("AdminSystem.Application"));

// 注册CsRedisClient

CSRedis.CSRedisClient csredis = new CSRedis.CSRedisClient(builder.Configuration.GetConnectionString("Redis"));

builder.Services.AddSingleton(csredis);

//注册HttpContext
builder.Services.AddHttpContextAccessor();

builder.Services.AddHostedService<BlogBackgroundService>();

//配置跨域
builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(policy =>
    {
        policy.WithOrigins(builder.Configuration["CorsSettings:Url"].Split(','))
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials();
    });
});


//注册内存缓存
builder.Services.AddMemoryCache();
builder.Services.AddDistributedMemoryCache();

// 默认使用内存存储（AddDistributedMemoryCache）
//builder.Services.AddCaptcha(builder.Configuration);

// 如果使用redis分布式缓存
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration.GetConnectionString("RedisCache");
    options.InstanceName = "captcha:";
});

// 全部配置
builder.Services.AddCaptcha(builder.Configuration, option =>
{
    option.CaptchaType = CaptchaType.WORD; // 验证码类型
    option.CodeLength = 6; // 验证码长度, 要放在CaptchaType设置后.  当类型为算术表达式时，长度代表操作的个数
    option.ExpirySeconds = 30; // 验证码过期时间
    option.IgnoreCase = true; // 比较时是否忽略大小写
    option.StoreageKeyPrefix = ""; // 存储键前缀

    option.ImageOption.Animation = true; // 是否启用动画
    option.ImageOption.FrameDelay = 30; // 每帧延迟,Animation=true时有效, 默认30

    option.ImageOption.Width = 150; // 验证码宽度
    option.ImageOption.Height = 40; // 验证码高度
    option.ImageOption.BackgroundColor = SkiaSharp.SKColors.White; // 验证码背景色

    option.ImageOption.BubbleCount = 2; // 气泡数量
    option.ImageOption.BubbleMinRadius = 5; // 气泡最小半径
    option.ImageOption.BubbleMaxRadius = 15; // 气泡最大半径
    option.ImageOption.BubbleThickness = 1; // 气泡边沿厚度

    option.ImageOption.InterferenceLineCount = 2; // 干扰线数量

    option.ImageOption.FontSize = 36; // 字体大小
    option.ImageOption.FontFamily = DefaultFontFamilys.Instance.Actionj; // 字体

    /* 
     * 中文使用kaiti，其他字符可根据喜好设置（可能部分转字符会出现绘制不出的情况）。
     * 当验证码类型为“ARITHMETIC”时，不要使用“Ransom”字体。（运算符和等号绘制不出来）
     */

    option.ImageOption.TextBold = true;// 粗体，该配置2.0.3新增
});



//Jwt
builder.Services.AddAuthentication(option =>
{
    option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(
                option =>
                {
                    option.TokenValidationParameters = new TokenValidationParameters
                    {
                        //是否验证发行人
                        ValidateIssuer = true,
                        ValidIssuer = builder.Configuration["JwtConfig:Bearer:Issuer"],//发行人

                        //是否验证受众人
                        ValidateAudience = true,
                        ValidAudience = builder.Configuration["JwtConfig:Bearer:Audience"],//受众人

                        //是否验证密钥
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JwtConfig:Bearer:SecurityKey"])),

                        ValidateLifetime = true, //验证生命周期

                        RequireExpirationTime = true, //过期时间

                        ClockSkew = TimeSpan.FromSeconds(30)   //平滑过期偏移时间
                    };
                }
            );

builder.Services.AddSwaggerGen(
    options =>
    {
        options.SwaggerDoc("v1", new OpenApiInfo { Title = "基础接口", Version = "v1" });
        options.SwaggerDoc("v2", new OpenApiInfo { Title = "业务接口", Version = "v2" });

        options.DocInclusionPredicate((doc, desc) =>
        {
            return desc.GroupName == doc;
        });


        //开启权限小锁
        options.OperationFilter<AddResponseHeadersFilter>();
        options.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
        options.OperationFilter<SecurityRequirementsOperationFilter>();
        options.CustomSchemaIds(type => type.FullName);

        //给参数设置默认值
        //options.SchemaFilter<SchemaFilter>();

        //在header中添加token，传递到后台
        options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
        {
            Description = "JWT授权(数据将在请求头中进行传递)直接在下面框中输入Bearer {token}(注意两者之间是一个空格) \"",
            Name = "Authorization",//jwt默认的参数名称
            In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
            Type = SecuritySchemeType.ApiKey
        });

        //就是这里！！！！！！！！！
        var basePath = AppDomain.CurrentDomain.BaseDirectory;
        var xmlPath = Path.Combine(basePath, "AdminSystem.WebApi.xml");//这个就是刚刚配置的xml文件名
        options.IncludeXmlComments(xmlPath, true);//默认的第二个参数是false，这个是controller的注释，记得修改
    }
);


builder.Host.UseWindowsService();

var app = builder.Build();


// Configure the HTTP request pipeline.
// 配置http请求管道----执行中间件
if (app.Environment.IsDevelopment())
{
    
}

app.UseSwagger();
app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "基础接口");
    c.SwaggerEndpoint("/swagger/v2/swagger.json", "业务接口");

    // 模型的默认扩展深度，设置为 -1 完全隐藏模型
    c.DefaultModelsExpandDepth(1);
    // API文档仅展开标记
    c.DocExpansion(DocExpansion.List);
    c.DefaultModelRendering(ModelRendering.Example);
    c.DefaultModelExpandDepth(-1);
    // API前缀设置为空
    c.RoutePrefix = string.Empty;
    // API页面Title
    c.DocumentTitle = "😍接口文档 - 阿星Plus⭐⭐⭐";
});

app.UseHttpsRedirection();

app.UseCors();

//认证
app.UseAuthentication();

//授权
app.UseAuthorization();

app.MapControllers();

app.Run();
